// 《围棋》作者版权所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// go:build ignore 
// +build ignore 

package main

import "strings"

// /注意：
// -小于64位的整数类型存在于寄存器的低部分。
// 现在，上面的部分是垃圾；符号/零扩展可能会在将来得到优化，但目前还没有。
// /-布尔类型为零或1；存储在字节中，但使用AMOVBZ加载，因此寄存器的高位字节为零。
// /-*常量指令可能使用大于指令编码的常数。
// 在本例中，汇编程序扩展为多条指令，并使用tmp 
// 寄存器（R31）。regalloc 

var regNamesPPC64 = []string{
	"SP", // REGSP 
	"SB", // REGSB 
	"R3",
	"R4",
	"R5",
	"R6",
	"R7",
	"R8",
	"R9",
	"R10",
	"R11", // REGCTXT用于闭包
	"R12",
	"R13", // REGTLS 
	"R14",
	"R15",
	"R16",
	"R17",
	"R18",
	"R19",
	"R20",
	"R21",
	"R22",
	"R23",
	"R24",
	"R25",
	"R26",
	"R27",
	"R28",
	"R29",
	"g",   // REGG。使用名称“g”并设置配置。哈斯格雷格让它“就这么发生了”。
	"R31", // REGTMP 

	"F0",
	"F1",
	"F2",
	"F3",
	"F4",
	"F5",
	"F6",
	"F7",
	"F8",
	"F9",
	"F10",
	"F11",
	"F12",
	"F13",
	"F14",
	"F15",
	"F16",
	"F17",
	"F18",
	"F19",
	"F20",
	"F21",
	"F22",
	"F23",
	"F24",
	"F25",
	"F26",
	"F27",
	"F28",
	"F29",
	"F30",
	"F31",

	// 如果添加寄存器，请在运行时更新asyncPreempt。

	// “CR0”，
	// “CR1”，
	// “CR2”，
	// “CR3”，
	// “CR5”，
	// “CR6”，
	// “CR7”，

	// “CR”，
	// “XER”，
}

func init() {
	if len(regNamesPPC64) > 64 {
		panic("too many registers")
	}
	num := map[string]int{}
	for i, name := range regNamesPPC64 {
		num[name] = i
	}
	buildReg := func(s string) regMask {
		m := regMask(0)
		for _, r := range strings.Split(s, " ") {
			if n, ok := num[r]; ok {
				m |= regMask(1) << uint(n)
				continue
			}
			panic("register " + r + " not found")
		}
		return m
	}

	var (
		gp = buildReg("R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29")
		fp = buildReg("F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26")
		sp = buildReg("SP")
		sb = buildReg("SB")
		gr = buildReg("g")
		// cr=buildReg（“cr”）
		// ctr=buildReg（“ctr”）
		// lr=buildReg（“lr”）
		tmp     = buildReg("R31")
		ctxt    = buildReg("R11")
		callptr = buildReg("R12")
		// tls=buildReg（“R13”）
		gp01        = regInfo{inputs: nil, outputs: []regMask{gp}}
		gp11        = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
		gp21        = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
		gp21a0      = regInfo{inputs: []regMask{gp, gp | sp | sb}, outputs: []regMask{gp}}
		gp31        = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
		gp22        = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp, gp}}
		gp32        = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp, gp}}
		gp1cr       = regInfo{inputs: []regMask{gp | sp | sb}}
		gp2cr       = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
		crgp        = regInfo{inputs: nil, outputs: []regMask{gp}}
		crgp11      = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}
		crgp21      = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
		gpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
		gploadidx   = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}}
		prefreg     = regInfo{inputs: []regMask{gp | sp | sb}}
		gpstore     = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
		gpstoreidx  = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}}
		gpstorezero = regInfo{inputs: []regMask{gp | sp | sb}} // ppc64。REGZERO是保留的零值
		gpxchg      = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}}
		gpcas       = regInfo{inputs: []regMask{gp | sp | sb, gp, gp}, outputs: []regMask{gp}}
		fp01        = regInfo{inputs: nil, outputs: []regMask{fp}}
		fp11        = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
		fpgp        = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
		gpfp        = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
		fp21        = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
		fp31        = regInfo{inputs: []regMask{fp, fp, fp}, outputs: []regMask{fp}}
		fp2cr       = regInfo{inputs: []regMask{fp, fp}}
		fpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{fp}}
		fploadidx   = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{fp}}
		fpstore     = regInfo{inputs: []regMask{gp | sp | sb, fp}}
		fpstoreidx  = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, fp}}
		callerSave  = regMask(gp | fp | gr)
		r3          = buildReg("R3")
		r4          = buildReg("R4")
		r5          = buildReg("R5")
		r6          = buildReg("R6")
	)
	ops := []opData{
		{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true},     // arg0+arg1 
		{name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "Int64"},     // arg0+生长素
		{name: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true},   // arg0+arg1 
		{name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true}, // arg0+arg1 
		{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"},                        // arg0-arg1 
		{name: "SUBFCconst", argLength: 1, reg: gp11, asm: "SUBC", aux: "Int64"},  // auxInt-arg0（带进位）

		{name: "MULLDconst", argLength: 1, reg: gp11, asm: "MULLD", aux: "Int32", typ: "Int64"}, // arg0*生长素（签名64位）
		{name: "MULLWconst", argLength: 1, reg: gp11, asm: "MULLW", aux: "Int32", typ: "Int64"}, // arg0*生长素（签名64位）
		{name: "MADDLD", argLength: 3, reg: gp31, asm: "MADDLD", typ: "Int64"},                  // （arg0*arg1）+arg2（签名64位）

		{name: "MULHD", argLength: 2, reg: gp21, asm: "MULHD", commutative: true},   // （arg0*arg1）>>64，签名
		{name: "LoweredMuluhilo", argLength: 2, reg: gp22, resultNotInArgs: true},   // arg0*arg1，返回（hi，lo）

		{name: "FMUL", argLength: 2, reg: fp21, asm: "FMUL", commutative: true},   // arg0*arg1 
		{name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true}, // arg0*arg1 

		{name: "FMADD", argLength: 3, reg: fp31, asm: "FMADD"},   // arg0*arg1+arg2 
		{name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS"}, // arg0*arg1+arg2 
		{name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB"},   // arg0*arg1-arg2 
		{name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS"}, // arg0*arg1-arg2 

		{name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // 
		{name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // 有符号的arg0>>（arg1和63），32位宽度
		{name: "SRD", argLength: 2, reg: gp21, asm: "SRD"},   // 无符号的arg0>>（arg1和127），64位宽度
		{name: "SRW", argLength: 2, reg: gp21, asm: "SRW"},   // 无符号的arg0>>（arg1和63），32位宽度

		{name: "ROTL", argLength: 2, reg: gp21, asm: "ROTL"},   // arg0按arg1 mod 64向左旋转
		{name: "ROTLW", argLength: 2, reg: gp21, asm: "ROTLW"}, // uint32（arg0）按arg1 mod 32向左旋转
		// /以下是按照ISA第C.8节所述实现移位扩展助记符的操作。
		// 常量移位值被压缩到aux int32中。
		{name: "RLDICL", argLength: 1, reg: gp11, asm: "RLDICL", aux: "Int32"},     // arg0提取移位参数“
		{name: "CLRLSLWI", argLength: 1, reg: gp11, asm: "CLRLSLWI", aux: "Int32"}, // 
		{name: "CLRLSLDI", argLength: 1, reg: gp11, asm: "CLRLSLDI", aux: "Int32"}, // 

		{name: "LoweredAdd64Carry", argLength: 3, reg: gp32, resultNotInArgs: true}, // arg0+arg1+进位，返回（和，进位）

		{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // 有符号的arg0>>生长素，0<=生长素<64，64位宽度
		{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // 有符号的arg0>>生长素，0<=生长素<32，32位宽度
		{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"},   // 无符号的arg0>>生长素，0<=生长素<64，64位宽度
		{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"},   // 无符号的arg0>>生长素，0<=生长素<32，32位宽度
		{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"},   // arg0<<auxInt，0<=auxInt<32，32位宽度

		{name: "ROTLconst", argLength: 1, reg: gp11, asm: "ROTL", aux: "Int64"},   // arg0由auxInt位向左旋转
		{name: "ROTLWconst", argLength: 1, reg: gp11, asm: "ROTLW", aux: "Int64"}, // uint32（arg0）由auxInt位向左旋转
		{name: "EXTSWSLconst", argLength: 1, reg: gp11, asm: "EXTSWSLI", aux: "Int64"},

		{name: "RLWINM", argLength: 1, reg: gp11, asm: "RLWNM", aux: "Int64"},                      // 通过立即“rlwinm”旋转和屏蔽。encodePPC64RotateMask描述辅助
		{name: "RLWNM", argLength: 2, reg: gp21, asm: "RLWNM", aux: "Int64"},                       // 通过“rlwnm”旋转和遮罩。encodePPC64RotateMask描述aux 
		{name: "RLWMI", argLength: 2, reg: gp21a0, asm: "RLWMI", aux: "Int64", resultInArg0: true}, // “rlwimi”与上述

		{name: "CNTLZD", argLength: 1, reg: gp11, asm: "CNTLZD", clobberFlags: true}, // 计数前导零
		{name: "CNTLZW", argLength: 1, reg: gp11, asm: "CNTLZW", clobberFlags: true}, // 计数前导零（32位）

		{name: "CNTTZD", argLength: 1, reg: gp11, asm: "CNTTZD"}, // 计数后继零
		{name: "CNTTZW", argLength: 1, reg: gp11, asm: "CNTTZW"}, // 计数后继零（32位）

		{name: "POPCNTD", argLength: 1, reg: gp11, asm: "POPCNTD"}, // arg0中的设置位数
		{name: "POPCNTW", argLength: 1, reg: gp11, asm: "POPCNTW"}, // arg0中每个字的设置位数放入相应的字
		{name: "POPCNTB", argLength: 1, reg: gp11, asm: "POPCNTB"}, // 放入相应字节

		{name: "FDIV", argLength: 2, reg: fp21, asm: "FDIV"},   // arg0/arg1 
		{name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS"}, // arg0/arg1 

		{name: "DIVD", argLength: 2, reg: gp21, asm: "DIVD", typ: "Int64"},   // arg0/arg1（有符号64位）
		{name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"},   // arg0/arg1（有符号32位）
		{name: "DIVDU", argLength: 2, reg: gp21, asm: "DIVDU", typ: "Int64"}, // arg0/arg1（无符号64位）
		{name: "DIVWU", argLength: 2, reg: gp21, asm: "DIVWU", typ: "Int32"}, // arg0/arg1（无符号32位）

		{name: "MODUD", argLength: 2, reg: gp21, asm: "MODUD", typ: "UInt64"}, // arg0%arg1（无符号64位）
		{name: "MODSW", argLength: 2, reg: gp21, asm: "MODSW", typ: "Int32"},  // arg0%arg1（有符号32位）
		// MOD被实现为rem:=arg0-（arg0/arg1）*arg1 

		// 转换都是浮点到浮点的寄存器操作。“整数”指FP寄存器中的编码。
		{name: "FCTIDZ", argLength: 1, reg: fp11, asm: "FCTIDZ", typ: "Float64"}, // 将浮点转换为64位整数向零进位
		{name: "FCTIWZ", argLength: 1, reg: fp11, asm: "FCTIWZ", typ: "Float64"}, // 将浮点转换为32位整数向零进位
		{name: "FCFID", argLength: 1, reg: fp11, asm: "FCFID", typ: "Float64"},   // 将64位整数转换为浮点
		{name: "FCFIDS", argLength: 1, reg: fp11, asm: "FCFIDS", typ: "Float32"}, // 将32位整数转换为浮点
		{name: "FRSP", argLength: 1, reg: fp11, asm: "FRSP", typ: "Float64"},     // 将浮点转换为32位值

		// 在浮点和整数寄存器之间移动，位不变；通过PPC上的存储+加载完成。
		// 由于32位加载字面值位指令的可寻址性较差，因此始终应扩宽
		// 数据，并使用FMOVDload和FMOVDstore（这也将避免端性问题）。
		// 应该应用一些优化——（Xi2f64（MOVWload（不添加ptr+offset）））可以使用
		// 字加载指令。（Xi2f64（MOVDload ptr））可以是（FMOVDload ptr）

		{name: "MFVSRD", argLength: 1, reg: fpgp, asm: "MFVSRD", typ: "Int64"},   // 将F寄存器的64位移到G寄存器
		{name: "MTVSRD", argLength: 1, reg: gpfp, asm: "MTVSRD", typ: "Float64"}, // 将G寄存器的64位移到F寄存器

		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},                    // arg0和arg1 
		{name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"},                                     // arg0和arg1 
		{name: "ANDCC", argLength: 2, reg: gp2cr, asm: "ANDCC", commutative: true, typ: "Flags"}, // arg0和arg1设置CC 
		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                      // arg0 | arg1 
		{name: "ORN", argLength: 2, reg: gp21, asm: "ORN"},                                       // arg0 | ^arg1 
		{name: "ORCC", argLength: 2, reg: gp2cr, asm: "ORCC", commutative: true, typ: "Flags"},   // arg0 | arg1集CC 
		{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},                    // ^（arg0 | arg1）
		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true},      // arg0^arg1 
		{name: "XORCC", argLength: 2, reg: gp2cr, asm: "XORCC", commutative: true, typ: "Flags"}, // arg0^arg1集CC 
		{name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true},      // arg0^^ arg1 
		{name: "NEG", argLength: 1, reg: gp11, asm: "NEG"},                                       // -arg0（整数）
		{name: "FCEIL", argLength: 1, reg: fp11, asm: "FRIP"},                                    // ceil（arg0），浮动64 
		{name: "FTRUNC", argLength: 1, reg: fp11, asm: "FRIZ"},                                   // trunc（arg0），浮动64 
		{name: "FROUND", argLength: 1, reg: fp11, asm: "FRIN"},                                   // round（arg0），浮动64 
		{name: "FABS", argLength: 1, reg: fp11, asm: "FABS"},                                     // abs（arg0），浮动64 
		{name: "FNABS", argLength: 1, reg: fp11, asm: "FNABS"},                                   // -abs（arg0），浮动64 
		{name: "FCPSGN", argLength: 2, reg: fp21, asm: "FCPSGN"},                                 // copysign arg0->arg1，浮动64 

		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"},                                                                                     // arg0 | aux 
		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"},                                                                                   // arg0^ aux 
		{name: "ANDconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}, asm: "ANDCC", aux: "Int64", clobberFlags: true}, // arg0和aux 
		{name: "ANDCCconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}}, asm: "ANDCC", aux: "Int64", typ: "Flags"},                             // arg0和aux==0 

		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", typ: "Int64"},   // sign extend int8到int64 
		{name: "MOVBZreg", argLength: 1, reg: gp11, asm: "MOVBZ", typ: "Int64"}, // zero extend uint8到uint64 
		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", typ: "Int64"},   // sign extend int16到int64 
		{name: "MOVHZreg", argLength: 1, reg: gp11, asm: "MOVHZ", typ: "Int64"}, // 

		// 按arch的尾数顺序将字节从arg0+aux+auxint加载到64位寄存器中。
		{name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // 加载字节零扩展
		{name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // 加载2字节符号扩展
		{name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // 加载2字节零扩展
		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // 加载4字节符号扩展
		{name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // 加载4字节零扩展
		{name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"},    // 加载8字节

		// 按arch的反尾数顺序将字节从arg0加载到64位寄存器，全部为零扩展。
		// 生成的指令是索引加载，指令中没有偏移量字段，因此不使用辅助字段。
		// 在这些情况下，索引寄存器字段设置为0，完整地址位于基址寄存器中。
		{name: "MOVDBRload", argLength: 2, reg: gpload, asm: "MOVDBR", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"}, // 加载8字节反向顺序
		{name: "MOVWBRload", argLength: 2, reg: gpload, asm: "MOVWBR", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // 加载4字节零扩展反向顺序
		{name: "MOVHBRload", argLength: 2, reg: gpload, asm: "MOVHBR", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // 加载2字节零扩展反向顺序

		// 在这些情况下，除了基址寄存器
		// 从内存位置arg[0]+arg[1]加载之外，还使用索引寄存器。
		{name: "MOVBZloadidx", argLength: 3, reg: gploadidx, asm: "MOVBZ", typ: "UInt8"},  // 零扩展uint8到uint64 
		{name: "MOVHloadidx", argLength: 3, reg: gploadidx, asm: "MOVH", typ: "Int16"},    // 符号扩展int16到int64 
		{name: "MOVHZloadidx", argLength: 3, reg: gploadidx, asm: "MOVHZ", typ: "UInt16"}, // 零扩展uint16到uint64 
		{name: "MOVWloadidx", argLength: 3, reg: gploadidx, asm: "MOVW", typ: "Int32"},    // 符号扩展int32到int64 
		{name: "MOVWZloadidx", argLength: 3, reg: gploadidx, asm: "MOVWZ", typ: "UInt32"}, // 零扩展uint32到uint64 
		{name: "MOVDloadidx", argLength: 3, reg: gploadidx, asm: "MOVD", typ: "Int64"},
		{name: "MOVWBRloadidx", argLength: 3, reg: gploadidx, asm: "MOVWBR", typ: "Int32"}, // 符号扩展int32到int64 
		{name: "MOVDBRloadidx", argLength: 3, reg: gploadidx, asm: "MOVDBR", typ: "Int64"},
		{name: "FMOVDloadidx", argLength: 3, reg: fploadidx, asm: "FMOVD", typ: "Float64"},
		{name: "FMOVSloadidx", argLength: 3, reg: fploadidx, asm: "FMOVS", typ: "Float32"},

		// 使用选项aux预取使用arg0和arg1生成的地址。arg0=addr，arg1=memory，aux=option。
		{name: "DCBT", argLength: 2, aux: "Int64", reg: prefreg, asm: "DCBT", hasSideEffects: true},

		// 将字节按arch的反尾端顺序存储到arg0中。
		// 这些是索引存储，指令中没有偏移量字段，因此不使用生长素字段。
		{name: "MOVDBRstore", argLength: 3, reg: gpstore, asm: "MOVDBR", aux: "Sym", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储8字节逆序
		{name: "MOVWBRstore", argLength: 3, reg: gpstore, asm: "MOVWBR", aux: "Sym", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储4字节逆序
		{name: "MOVHBRstore", argLength: 3, reg: gpstore, asm: "MOVHBR", aux: "Sym", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储2字节逆序

		// 从arg0+aux+auxint加载浮点
		{name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // 加载双浮点
		{name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // 加载单浮点数

		// 按arch的尾数顺序将字节存储到arg0+aux+auxint 
		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储字节
		{name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储2字节
		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储4字节
		{name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储8字节

		// 将浮点值存储到arg0+aux+auxint 
		{name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储双浮点数

		// 使用索引和基寄存器存储
		// 存储到arg[0]+arg[1]
		{name: "MOVBstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVB", typ: "Mem"},     // 存储bye 
		{name: "MOVHstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVH", typ: "Mem"},     // 存储半字
		{name: "MOVWstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVW", typ: "Mem"},     // 存储字
		{name: "MOVDstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVD", typ: "Mem"},     // 存储双字
		{name: "FMOVDstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVD", typ: "Mem"},   // 存储双浮点数
		{name: "FMOVSstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVS", typ: "Mem"},   // 存储单浮点数
		{name: "MOVHBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVHBR", typ: "Mem"}, // 存储半字反向字节使用索引reg 
		{name: "MOVWBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVWBR", typ: "Mem"}, // 使用索引reg 
		{name: "MOVDBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVDBR", typ: "Mem"}, // 存储双字反转字节使用索引reg 

		// 以下操作将0存储到arg0+aux+auxint arg1=mem 
		{name: "MOVBstorezero", argLength: 2, reg: gpstorezero, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储零1字节
		{name: "MOVHstorezero", argLength: 2, reg: gpstorezero, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储零2字节
		{name: "MOVWstorezero", argLength: 2, reg: gpstorezero, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储零4字节
		{name: "MOVDstorezero", argLength: 2, reg: gpstorezero, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 存储零8字节

		{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{sp | sb | gp}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0+auxInt+aux。（*gc.Sym），arg0=SP/SB/GP 

		{name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", typ: "Int64", rematerializeable: true}, // 
		{name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", rematerializeable: true},           // 
		{name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float32", asm: "FMOVS", rematerializeable: true},           // 
		{name: "FCMPU", argLength: 2, reg: fp2cr, asm: "FCMPU", typ: "Flags"},

		{name: "CMP", argLength: 2, reg: gp2cr, asm: "CMP", typ: "Flags"},     // arg0与arg1 
		{name: "CMPU", argLength: 2, reg: gp2cr, asm: "CMPU", typ: "Flags"},   // arg0与arg1 
		{name: "CMPW", argLength: 2, reg: gp2cr, asm: "CMPW", typ: "Flags"},   // arg0与arg1 
		{name: "CMPWU", argLength: 2, reg: gp2cr, asm: "CMPWU", typ: "Flags"}, // arg0与arg1 
		{name: "CMPconst", argLength: 1, reg: gp1cr, asm: "CMP", aux: "Int64", typ: "Flags"},
		{name: "CMPUconst", argLength: 1, reg: gp1cr, asm: "CMPU", aux: "Int64", typ: "Flags"},
		{name: "CMPWconst", argLength: 1, reg: gp1cr, asm: "CMPW", aux: "Int32", typ: "Flags"},
		{name: "CMPWUconst", argLength: 1, reg: gp1cr, asm: "CMPWU", aux: "Int32", typ: "Flags"},

		// ISEL生长素值0=LT 1=GT 2=arg2？arg0:arg1 
		// ISEL生长素值4=GE 5=LE 6=NE！arg2？arg1:arg0 
		// ISELB特例，其中arg0，arg1值为0，布尔结果为1 
		{name: "ISEL", argLength: 3, reg: crgp21, asm: "ISEL", aux: "Int32", typ: "Int32"},  // 请参见上面的
		{name: "ISELB", argLength: 2, reg: crgp11, asm: "ISEL", aux: "Int32", typ: "Int32"}, // 请参见上面的

		// 伪操作
		{name: "Equal", argLength: 1, reg: crgp},         // bool，true标志encode x==y false，否则。
		{name: "NotEqual", argLength: 1, reg: crgp},      // bool，真标志编码x=否则就错了。
		{name: "LessThan", argLength: 1, reg: crgp},      // bool，true标志编码x<y，否则为false。
		{name: "FLessThan", argLength: 1, reg: crgp},     // bool，true标志编码x<y，否则为false。
		{name: "LessEqual", argLength: 1, reg: crgp},     // bool，true标志编码x<=y，否则为false。
		{name: "FLessEqual", argLength: 1, reg: crgp},    // bool，真标志编码x<=y，否则为假；PPC<==！>这对于NaN 
		{name: "GreaterThan", argLength: 1, reg: crgp},   // bool是错误的，否则真标志编码x>y false。
		{name: "FGreaterThan", argLength: 1, reg: crgp},  // bool，true标志编码x>y，否则为false。
		{name: "GreaterEqual", argLength: 1, reg: crgp},  // bool，true标志编码x>=y，否则为false。
		{name: "FGreaterEqual", argLength: 1, reg: crgp}, // bool，true标志编码x>=y，否则为false。；PPC>==！<NaN 

		// 调度程序确保LoweredGetClosurePtr只出现在入口块
		// 中，并将其排序到块的最开始，以防止其他
		// 使用闭包指针。
		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{ctxt}}, zeroWidth: true},

		// LoweredGetCallerSP返回当前函数调用方的SP。
		{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},

		// LoweredGetCallerPC计算其“调用者”将返回的PC。
		// 也就是说，如果f调用g“调用”GetCallerRPC，
		// 结果应该是g将返回的f内的PC。
		// 请参阅运行时/stubs。进行更详细的讨论。
		{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},

		// arg0=ptr，arg1=mem，返回void。如果ptr为零，则出现故障。
		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
		// 四舍五入运算以阻止融合乘加提取。
		{name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true},
		{name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true},

		{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                       // 调用静态函数aux。（*obj.LSym）。arg0=mem，auxint=argsize，返回mem 
		{name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true},                         // tail call静态函数aux。（*obj.LSym）。arg0=mem，auxint=argsize，返回mem 
		{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{callptr, ctxt, 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // 通过闭包调用函数。arg0=codeptr，arg1=closure，arg2=mem，auxint=argsize，返回mem 
		{name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{callptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},            // 通过指针调用fn。arg0=codeptr，arg1=mem，auxint=argsize，返回mem 

		// 大或未对齐的归零
		// arg0=内存地址为零（在R3中，更改为副作用）
		// 返回mem 
		// 
		// 当有多个迭代
		// 需要清除4个双字
		// 
		// XXLXOR VS32，VS32 
		// MOVD$len/32，R31 
		// MOVD R31，CTR 
		// MOVD$16，R31 
		// loop:
		// STXVD2X VS32，（R0）（R3）
		// STXVD2X VS32，（R31），R3）
		// 添加R3,32 

		// MOVD R0,8（R3）
		// MOVD R0,16（R3）
		// MOVD R0,24（R3）

		// 其中一个或多个用于清除剩余<8字节的
		// MOVH R0，n2（R3）
		{
			name:      "LoweredZero",
			aux:       "Int64",
			argLength: 2,
			reg: regInfo{
				inputs:   []regMask{buildReg("R20")},
				clobbers: buildReg("R20"),
			},
			clobberFlags:   true,
			typ:            "Mem",
			faultOnNilArg0: true,
			unsafePoint:    true,
		},
		{
			name:      "LoweredZeroShort",
			aux:       "Int64",
			argLength: 2,
			reg: regInfo{
				inputs: []regMask{gp}},
			typ:            "Mem",
			faultOnNilArg0: true,
			unsafePoint:    true,
		},
		{
			name:      "LoweredQuadZeroShort",
			aux:       "Int64",
			argLength: 2,
			reg: regInfo{
				inputs: []regMask{gp},
			},
			typ:            "Mem",
			faultOnNilArg0: true,
			unsafePoint:    true,
		},
		{
			name:      "LoweredQuadZero",
			aux:       "Int64",
			argLength: 2,
			reg: regInfo{
				inputs:   []regMask{buildReg("R20")},
				clobbers: buildReg("R20"),
			},
			clobberFlags:   true,
			typ:            "Mem",
			faultOnNilArg0: true,
			unsafePoint:    true,
		},

		// R31是临时寄存器
		// 循环代码：
		// MOVD len/32，R31设置循环ctr 
		// MOVD R31，CTR 
		// MOVD$16，R31索引寄存器
		// loop:
		// LXVD2X（R0）（R4），VS32 
		// LXVD2X（R31）（R4），VS33 
		// ADD R4，$32增量src 
		// BC 16,0，循环分支ctr 
		// 为此，VS32和VS33被视为
		// 暂存寄存器。由于regalloc不跟踪向量寄存器，即使它可能被标记为clobbered，也没有效果。
		// TODO:如果向量寄存器由regalloc 
		// 管理，请将其标记为clobbered。
		// 
		// 未被此循环移动的字节将被移动
		// 结合以下指令，
		// 从最大的大小开始，并根据需要使用适当的偏移值生成多个
		// 字节。MOVD n（R4），R14 

		{
			name:      "LoweredMove",
			aux:       "Int64",
			argLength: 3,
			reg: regInfo{
				inputs:   []regMask{buildReg("R20"), buildReg("R21")},
				clobbers: buildReg("R20 R21"),
			},
			clobberFlags:   true,
			typ:            "Mem",
			faultOnNilArg0: true,
			faultOnNilArg1: true,
			unsafePoint:    true,
		},
		{
			name:      "LoweredMoveShort",
			aux:       "Int64",
			argLength: 3,
			reg: regInfo{
				inputs: []regMask{gp, gp},
			},
			typ:            "Mem",
			faultOnNilArg0: true,
			faultOnNilArg1: true,
			unsafePoint:    true,
		},

		// LXV代替LXVD2X，LXVD2X不需要索引
		// 寄存器，并且将在循环中执行4而不是仅执行4。
		{
			name:      "LoweredQuadMove",
			aux:       "Int64",
			argLength: 3,
			reg: regInfo{
				inputs:   []regMask{buildReg("R20"), buildReg("R21")},
				clobbers: buildReg("R20 R21"),
			},
			clobberFlags:   true,
			typ:            "Mem",
			faultOnNilArg0: true,
			faultOnNilArg1: true,
			unsafePoint:    true,
		},

		{
			name:      "LoweredQuadMoveShort",
			aux:       "Int64",
			argLength: 3,
			reg: regInfo{
				inputs: []regMask{gp, gp},
			},
			typ:            "Mem",
			faultOnNilArg0: true,
			faultOnNilArg1: true,
			unsafePoint:    true,
		},

		{name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true},

		{name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, typ: "UInt8", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},
		{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, typ: "UInt32", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},
		{name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, typ: "Int64", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},
		{name: "LoweredAtomicLoadPtr", argLength: 2, reg: gpload, typ: "Int64", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},

		// 原子地址32，64 
		// LWSYNC 
		// LDAR（Rarg0），路由
		// 添加Rarg1，路由
		// STDCCC路由，（Rarg0）
		// BNE-3（PC）
		// 返回新的金额
		{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},

		// ，Rout 
		// STDCCC Rarg1，（Rarg0）
		// BNE-2（PC）
		// ISYNC 
		// 返回旧值
		{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},

		// 原子比较和交换。
		// arg0=指针，arg1=旧值，arg2=新值，arg3=内存。生长素必须为零。
		// if*arg0==arg1{
		// *arg0=arg2 
		// 返回（真，内存）
		// }否则{
		// 返回（假，内存）
		// }
		// 同步
		// BNE 3（PC）
		// STDCCC Rarg2，（Rarg0）
		// BNE-4（PC）
		// CBNZ Rtmp，-4（PC）
		// CSET EQ，Rout 
		{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, aux: "Int64", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, aux: "Int64", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},

		// atomic 8/32和/或。
		// /*arg0&=（|=）arg1。arg2=mem。返回内存。生长素必须为零。
		// LBAR/LWAT（Rarg0），Rtmp 
		// 和/或Rarg1，Rtmp 
		// STBCCC/STWCCC Rtmp，（Rarg0），Rtmp 
		// BNE Rtmp，-3（PC）
		{name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicAnd32", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicOr32", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true},

		// LoweredWB调用运行时。gcWriteBarrier。arg0=destptr，arg1=srcptr，arg2=mem，aux=runtime。gcWriteBarrier 
		// 它保留R0到R17（特殊寄存器R1、R2、R11、R12、R13除外）、g及其参数R20和R21，
		// 但可能会删除任何其他内容，包括R31（REGTMP）。
		{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ buildReg("R0 R3 R4 R5 R6 R7 R8 R9 R10 R14 R15 R16 R17 R20 R21 g")) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"},

		// 其中有三个函数，因此它们可以有三个不同的寄存器输入。
		// 当我们检查0<=c<=cap（A），然后检查0<=b<=c（b），然后检查0<=A<=b（c）时，我们希望
		// 默认寄存器匹配，所以我们不需要不必要地复制寄存器。
		{name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r6}}, typ: "Mem", call: true}, // arg0=idx，arg1=len，arg2=mem，返回内存。AuxInt包含报告代码（参见genericOps.go中的PanicBounds）。
		{name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r4, r5}}, typ: "Mem", call: true}, // arg0=idx，arg1=len，arg2=mem，返回内存。AuxInt包含报告代码（参见genericOps.go中的PanicBounds）。
		{name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r3, r4}}, typ: "Mem", call: true}, // arg0=idx，arg1=len，arg2=mem，返回内存。AuxInt包含报告代码（参见genericOps.go中的PanicBounds）。

		// （反向标志（CMPA））==（CMPB a）
		// 所以如果我们想要（LessThan（CMPA b）），但我们不能这样做，因为a是一个常数，
		// 那么我们改为（LessThan（反向标志（CMPB）））。
		// 重写会将其转换为（大于（CMP b a））。
		// InvertFlags是一个伪操作，不能出现在程序集输出中。
		{name: "InvertFlags", argLength: 1}, // arg0的反向

		// 常量标志值。对于任何比较，有三种可能的结果：有符号的总订单中的三个（<，=，>）或无符号的总订单中的三个，具体取决于哪个
		// 使用了比较操作（CMP或CMPU--PPC不同于
		// 其他体系结构，它们使用单个比较生成
		// 有符号和无符号比较结果。）

		// 这些操作是供重写规则临时使用的。它们
		// 不能出现在生成的程序集中。
		{name: "FlagEQ"}, // 相等
		{name: "FlagLT"}, // 有符号<或无符号<
		{name: "FlagGT"}, // 有符号>或无符号>
	}

	blocks := []blockData{
		{name: "EQ", controls: 1},
		{name: "NE", controls: 1},
		{name: "LT", controls: 1},
		{name: "LE", controls: 1},
		{name: "GT", controls: 1},
		{name: "GE", controls: 1},
		{name: "FLT", controls: 1},
		{name: "FLE", controls: 1},
		{name: "FGT", controls: 1},
		{name: "FGE", controls: 1},
	}

	archs = append(archs, arch{
		name:               "PPC64",
		pkg:                "cmd/internal/obj/ppc64",
		genfile:            "../../ppc64/ssa.go",
		ops:                ops,
		blocks:             blocks,
		regnames:           regNamesPPC64,
		ParamIntRegNames:   "R3 R4 R5 R6 R7 R8 R9 R10 R14 R15 R16 R17",
		ParamFloatRegNames: "F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12",
		gpregmask:          gp,
		fpregmask:          fp,
		framepointerreg:    -1,
		linkreg:            -1, // 未使用
	})
}
